#!/bin/sh
#(c) Copyright Barry Kauler LGPL v2 2006,2007 www.puppylinux.com
# - shutdownconfig creates the pupsave (savefile, savefolder)
# - for a full hd install, PUPMODE=2 (no /initrd)
# /etc/inittab: ::shutdown:/etc/rc.d/rc.shutdown

export RC_SHUTDOWN=1
export TERM=rxvt

[ -f /tmp/debugshutdown ] && exec &>/dev/console

export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin

export TEXTDOMAIN=rc.shutdown
export OUTPUT_CHARSET=UTF-8
L_UNMOUNTING="$(gettext "Unmounting '%s' ...")"
L_UNMOUNTING_STRAY="$(gettext 'Unmounting stray filesystems:')"

BB=/bin/busybox

if [ ! -f /tmp/debugshutdown ] ; then
	clear
	exec 1> /dev/null 2>&1
fi

#if don't do this, may be locked at next boot...
which rfkill &>/dev/null && rfkill unblock all

. /etc/rc.d/PUPSTATE #variables created at bootup by init script in initrd...
. /etc/DISTRO_SPECS
. /etc/eventmanager	# 140417, SFR

PUPSFSFILE="`echo "$PUPSFS" | cut -f 3 -d ','`" #/etc/rc.d/PUPSTATE
PSUBDIR="`dirname "$PUPSFSFILE"`"
[ "$PSUBDIR" = "/" ] && PSUBDIR=""
[ $PUPMODE -eq 5 ] && [ "$DEV1FS" = "iso9660" ] && PSUBDIR="" #100920 booting off cd, always default have savefile at /.
[ $PUPMODE -eq 5 ] && [ "$DEV1FS" = "udf" ] && PSUBDIR=""     #ditto, for udf f.s.
[ "$DEV1FS" = "msdos" ] && DEV1FS="vfat" #110919

killzombies() { #zombie process prevents partition unmount.
 #karl godt: see http://www.murga-linux.com/puppy/viewtopic.php?t=73122
 ZOMBIES="`ps -H -A | grep '<defunct>' | sed 's/^[[:blank:]]*//g' | cut -f 1 -d ' ' | sort -gr | tr '\n' ' '`"
 for ONEZOMBIE in $ZOMBIES ; do
   echo "Killing parentless zombie process $ONEZOMBIE"
   ps --no-header -p $ONEZOMBIE && kill $ONEZOMBIE
 done
}

echo "${DISTRO_NAME} ${DISTRO_VERSION} $(gettext 'is now shutting down...')" > /dev/console
echo "Executing /etc/rc.d/rc.shutdown..."

# improper shutdown check. see /etc/rc.d/rc.sysinit, /init in initramfs, and /sbin/init...
if [ -f /fsckme.flg -a ! -f /tmp/bootsysinit_must_fsck ] ; then
  rm -f /fsckme.flg
fi
[ -f /initrd${PUP_HOME}/fsckme.flg ] && rm -f /initrd${PUP_HOME}/fsckme.flg

#v2.0.0 there could be a save tmpfs->persistent-storage running...
while [ "`pidof snapmergepuppy`" ]; do sleep 1 ; done

cd /
sync
echo "Killing X and all X apps..."
killall -9 X > /dev/null 2>&1 #just a precaution...
sleep 1
killall -3 X > /dev/null 2>&1
sync

#MU warns may need to do this for dillo...
killall file.dpi 2>/dev/null
killall bookmarks.dpi 2>/dev/null
killall dpid 2>/dev/null

# some packages have a service script that requires stopping...
for service_script in $(ls /etc/init.d/* | sort -r)
do
	[ -x $service_script ] && $service_script stop
done
#note, /etc/rc.d/rc.services does same, with 'start' parameter.

[ "$PUNIONFS" = "aufs" ] && sfs_load --cli stop

### cleanly unmount cifs shares from /usr/share/Shares
# must be done here otherwise hang later at mount -a -r at rc.cleanup
# samba rox app
find /usr/share/Shares/ -maxdepth 2 -name mnt-point | while read p; do
	case $p in
		"") break ;;
		*)  if grep -q $p /proc/mounts; then
				fuser -mk $p 
				${p%/*}/AppRun unmount
			fi ;;
	esac
done
# yassm
for p in $(awk '$2 ~ "YASSM" {print $2}' /proc/mounts); do
	fuser -mk $p 
	umount $p
done
#01micko: umount is not a reliable script, so have to use umount-FULL
#also see shinobar's msg in http://murga-linux.com/puppy/viewtopic.php?p=605451#605451
umount-FULL -a -t cifs,smbfs,nfs,sshfs
###

#100902 rerwin: log the cumulative bytes transmitted on dialup...
which modemdisconnect >/dev/null && modemdisconnect #(if connected)

#100301 brought down below call to 'stop' service scripts, needed for lamesmbxplorer.
#100814 log the cumulative bytes transmitted on network
# (see also /etc/rc.d/rc.sysinit and network_tray)
#bring down network interfaces (prevents shutdown sometimes)...
networkdisconnect --shutdown #181209

#100604 reported by shel: http://murga-linux.com/puppy/viewtopic.php?t=56238
# Unload the Ethernet drivers on shutdown to prevent battery drain.
for i in /sys/class/net/* ; do
	if [ -e "${i}" -a -e ${i}/device/driver ] ; then
		driver=$(readlink ${i}/device/driver)
		modprobe -r ${driver##*/} #basename $driver
	fi
done

killall udevd > /dev/null 2>&1

#first time booted puppy, there may not have been any persistent storage...
if [ $PUPMODE -eq 5 ];then
 # shutdownconfig creates /tmp/shutdownconfig_results
 # which contains variables to be used further in the script
 unset PUPSAVE SAVEFS SAVEPART SAVEFILE NAMEONLY SAVEPATH MYPASSWORD SFEXT xPDEV xDEVFS
 if [ ! -f /tmp/shutdownconfig_results ];then
   #note, shutdownconfig normally called via /usr/bin/wmreboot or wmpoweroff when want shutdown from X.
   shutdownconfig > /dev/console
 fi
 if [ -s /tmp/shutdownconfig_results ];then
   . /tmp/shutdownconfig_results #supplies variables PUPMODE SAVEFS PUPSAVE SAVEPART SAVEFILE NAMEONLY SAVEPATH MYPASSWORD SFEXT
   cp /tmp/shutdownconfig_results /tmp/rc.shutdown_config # read by /usr/sbin/savesession-dvd
   rm -f /tmp/shutdownconfig_results #precaution.
 fi
fi #end ifpupmode5

if [ "$PUPSAVE" != "" ];then
 #f.s. and partition where ${DISTRO_FILE_PREFIX}save.2fs is located...
 SAVEFS="`echo -n "$PUPSAVE" | cut -f 2 -d ','`"
 SAVEPART="`echo -n "$PUPSAVE" | cut -f 1 -d ','`"
 SAVEFILE="`echo -n "$PUPSAVE" | cut -f 3 -d ','`"
fi

[ ! -f /tmp/debugshutdown ] && clear >/dev/console

cp -f /etc/profile /var/local/etc_profile_at_shutdown #bad hack, see /etc/rc.d/rc.update.
#120629 raspberry pi does not have a hw clock. save here, read at bootup (see rc.country)...
DATESAVE="`date "+%Y-%m-%d %H:%M:%S"`" #ex: 2018-07-30 06-27-38 #busybox compatible..
echo -n "$DATESAVE" > /var/local/shutdown_date_saved
#when the working files run in tmpfs in ram, they are saved (below) and /tmp and /var
#are screened out. however, some PUPMODES mount ${DISTRO_FILE_PREFIX}save.2fs directly on /initrd/pup_rw,
#the top aufs layer, meaning that there is no intermediary tmpfs in ram for working
#files, hence everything is saved directly, ditto for PUPMODE=2 a full h.d. install.
#hence need to do some explicit wiping here...

# underdog - remove whiteout files for mounted underdog
if [ "$(mount | grep "/pup_ud")" != "" ]; then
    if [ -e /initrd/pup_ud/etc/xdg/autostart ]; then
	  for dfile in $(ls -1 /initrd/pup_ud/etc/xdg/autostart 2>/dev/null) ; do
	   [ -e /initrd/pup_rw/etc/xdg/autostart/.wh.$dfile ] && rm -f /initrd/pup_rw/etc/xdg/autostart/.wh.$dfile
	  done
    fi
    if [ -e /initrd/pup_ud/etc/init.d ]; then
      rm -f /initrd/pup_rw/etc/init.d/.wh.rcS 2>/dev/null
      rm -f /initrd/pup_rw/etc/init.d/.wh.rCS 2>/dev/null
      rm -f /initrd/pup_rw/etc/init.d/.wh.rc 2>/dev/null
	  for dfile in $(ls -1 /initrd/pup_ud/etc/init.d 2>/dev/null) ; do
	    [ -e /initrd/pup_rw/etc/init.d/.wh.$dfile ] && rm -f /initrd/pup_rw/etc/init.d/.wh.$dfile
	  done
    fi
fi

cat /var/log/messages* > /var/log/previous.messages
rm -f /var/log/messages*
rm -f /var/lock/LCK*
rm -f /var/run/*.pid
rm -rf /root/tmp 2> /dev/null #...note, not screening this out in any of above save modes.
rm -rf /root/.thumbnails/* 2> /dev/null
[ -d /var/tmp ] && rm -rf /var/tmp/* 2> /dev/null #100820
rm -f /tmp/geany_socket* 2>/dev/null #if geany still running at shutdown
[ -d /root/.config/geany ] && rm -f /root/.config/geany/geany_socket* 2>/dev/null
[ -f /etc/rc.d/MORESFS ] && rm /etc/rc.d/MORESFS
sync

# 140417, SFR
asktosave_func () {
 if [ "$ASKTOSAVE" = "false" ]; then
   RETVAL=0
 else
   dialog --timeout 60 --yes-label "$(gettext 'SAVE')" --no-label "$(gettext 'NO SAVE')" --yesno "$(gettext 'Press ENTER key to save session... 
Or, press TAB then ENTER to not save session... 
Or, wait 60 seconds to shutdown without saving session...')" 0 0 >/dev/console 
   RETVAL=$?
 fi
 [ $RETVAL -ne 0 ] && echo "$(gettext "Session not saved")" >/dev/console
 return $RETVAL
}

#save session...
case $PUPMODE in
 5) #v2.02 first boot.
  echo "$(gettext "Session not saved")" >/dev/console
  sync
  #ha ha, before had this, if aborted save after choosing save-partition, code
  #further down wiped all of the partition (it was mntd on /tmp/savepup)...
  [ ! "$SMNTPT" = "" ] && umount $SMNTPT 2>/dev/null
  #...well, fixed it, changed mntpt so not in /tmp. Leave above line here.
  ;;
 128) #1st shutdown, save to ${DISTRO_FILE_PREFIX}save.2fs.
  #partition already mounted on $SMNTPT.
  echo "$(printf "$(gettext 'Saving session to %s file on %s partition...')" "${SAVEFILE}" "${SAVEPART}")" >/dev/console
  mkdir /tmp/save1stpup
  echo -n "Mounting ${SAVEFILE}..."
  FILEFS="ext3"
  echo -n "$SAVEFILE" | grep -q "2fs" && FILEFS="ext2"
  echo -n "$SAVEFILE" | grep -q "4fs" && FILEFS="ext4" # 01micko
  if [ -d $SMNTPT$SAVEFILE ]; then
   rm -r -f  /tmp/save1stpup
   ln -s $SMNTPT$SAVEFILE /tmp/save1stpup
  elif [ "$CRYPTO" = "" ];then
   mount -t $FILEFS -o noatime,rw,loop $SMNTPT$SAVEFILE /tmp/save1stpup
  else
   DEVLOOP="`losetup -f`"
   losetup $DEVLOOP ${SMNTPT}$SAVEFILE
   echo -n "$MYPASSWORD" | cryptsetup luksOpen $DEVLOOP savefile -
   [ ! $? -eq 0 ] && exit 1
   mount -t $FILEFS -o noatime,rw /dev/mapper/savefile /tmp/save1stpup
  fi
  #120522 testing precise puppy with aufs, have two dirs here .wh..wh.orph, .wh..wh.plnk, filter out...
  RDIRS="`find /initrd/pup_rw/ -mindepth 1 -maxdepth 1 -mount -type d | grep -v '/\.wh\.' | grep -v -E '/$|/mnt|/tmp|/proc|/sys|/dev|/lost' | tr '\n' ' '`"
  for ONEDIR in $RDIRS
  do
   BASENAME="`basename $ONEDIR`"
   # set owner/permission of dirs when 1st save. this is important when choose to run as finn on 1st shutdown.
   if [ ! -d /tmp/save1stpup/${BASENAME} ];then
    mkdir -p /tmp/save1stpup/${BASENAME}
    #110503 got this from /usr/sbin/snapmergepuppy...
    chmod "/tmp/save1stpup/${BASENAME}" --reference="$ONEDIR"
    OWNER="`stat -c %U "$ONEDIR"`"
    chown $OWNER "/tmp/save1stpup/${BASENAME}"
    GRP="`stat -c %G "$ONEDIR"`"
    chgrp $GRP "/tmp/save1stpup/${BASENAME}"
    touch "/tmp/save1stpup/${BASENAME}" --reference="$ONEDIR"
   fi
   cp -a $ONEDIR/ /tmp/save1stpup/
  done
  #copy initmodules config file from /tmp if it exists
  [ -f /tmp/${DISTRO_FILE_PREFIX}initmodules.txt ] && cp -f /tmp/${DISTRO_FILE_PREFIX}initmodules.txt ${SMNTPT}${SAVEPATH}/${DISTRO_FILE_PREFIX}initmodules.txt
  sync
  if [ ! -L /tmp/save1stpup ] ; then
    umount /tmp/save1stpup
    [ "$CRYPTO" = "luks" ] && cryptsetup luksClose savefile
  fi

  umount $SMNTPT 2> /dev/null
 ;;

 77) /usr/sbin/savesession-dvd ;; #requires /tmp/rc.shutdown_config - save to folder on multisession CD/DVD (including 1st shutdown)
 2)  echo -n ;; #echo "$(printf "$(gettext '%s mounted directly, session already saved.')" "$PDEV1")" >/dev/console
 12) echo "$(printf "$(gettext '%s mounted directly top layer, session already saved.')" "${SAVEFILE##*/}")" >/dev/console ;;
 13) #PDEV1 and PUPSFS and PUPSAVE 
  #/initrd/pup_rw has tmpfs, pup_ro1 has ${DISTRO_FILE_PREFIX}save.2fs file (PUPSAVE), pup_ro2 has PUPSFS file. 
  #the above are in aufs at /.
  asktosave_func
  if [ $? -eq 0 ]; then 
    echo "$(printf "$(gettext 'Saving session to %s (%s)...')" "${SAVEFILE}" "${SAVEPART}")" >/dev/console
    /usr/sbin/snapmergepuppy /initrd/pup_ro1 /initrd/pup_rw
  fi 
  ;;
 *)
  echo "$(gettext "Session not saved")" >/dev/console
  sleep 2
  ;;
esac

# ==============================================================

sync

swapoff -a #works only if swaps are in mtab or ftab
STRAYPARTD="`cat /proc/swaps | grep "/" | cut -f 1 -d " " | tr "\n" " "`"
for S in $STRAYPARTD ; do swapoff $S ; done

# Karl Godt: 2013-12-14 reworked the whole unmount block
MOUNTED=`tac /proc/mounts | grep -vE '/dev |/dev/root | rootfs | / | usbfs | aufs | tmpfs ' | cut -f2 -d' '`
STRAY_MOUNTPOINTS=`echo "$MOUNTED" | grep -vE '/proc|/sys|/initrd|/dev |/dev/pts'`
[ "$STRAY_MOUNTPOINTS" ] && echo "$L_UNMOUNTING_STRAY" >/dev/console
sync

for MOUNT_POINT in $STRAY_MOUNTPOINTS ; do
 MOUNT_POINT=`busybox echo -e "$MOUNT_POINT"` # formats escaped chars like \040 to literal like ' ' (space)
 echo "$(printf "$L_UNMOUNTING" "$MOUNT_POINT")" >/dev/console
 FLAGCIFS=`echo -n "${MOUNT_POINT}" | grep '^//'`
 if [ ! "$FLAGCIFS" ]; then
  xFUSER=`busybox fuser -m "$MOUNT_POINT" 2>/dev/null`
  [ "$xFUSER" ] && busybox fuser -k -m "$MOUNT_POINT"
 fi
  killzombies
 sync
 umount -r "$MOUNT_POINT" # karl godt.
done
sync

# old code to attempt to free the PDEV1 (PDRV) [doen't seem to work]
# - "note, there is a problem with unmounting, especially ntfs as it cannot be
#    remounted ro. A ntfs part with ${DISTRO_FILE_PREFIX}save.2fs cannot be unmounted"
BPS="`ps -A`"
SHID="`echo "$BPS" | grep ' -sh$' | head -n 1 | sed -e 's%^ %%g' | cut -f 1 -d ' '`"
MYPID=$$
PARENT=$PPID # id of parent process. variable provided by system.
[ ! "$PUP_HOME" ] && PUP_HOME="/mnt/dev_save"
if [ "`busybox mount | grep "/initrd${PUP_HOME}"`" != "" ];then
	BADPIDS="`busybox fuser -m $ABSPUPHOME 2>/dev/null | tr -d 'm'`"
	for ONEBAD in $BADPIDS ; do
		case "$ONEBAD" in $MYPID|$PARENT|$SHID) continue ;; esac
		echo "Killing process $ONEBAD..." >/dev/console
		kill $ONEBAD || { sleep 1 ; kill -9 $ONEBAD 2>/dev/null ; }
		sleep 1
		sync
	done
	killzombies
fi

#=======================================================

PIVOT_INITRD=
if [ -f /tmp/shutdown_pivot_initrd ] ; then # /sbin/poweroff
	PIVOT_INITRD=1
fi

# remount PUNIONFS read-only
if [ "$SAVE_LAYER" ];then
	SAVEDEV=`grep "/initrd${SAVE_LAYER}" /proc/mounts | cut -f 1 -d ' '`
	SAVEFS=`grep "/initrd${SAVE_LAYER}" /proc/mounts | cut -f 3 -d ' '`
	#Patriot suggested this code to enable save-layer to remount ro...
	uniFS=$(awk '/unionfs/ {print $3}' /proc/mounts) #gets fstype, ex: aufs
	if [ "$uniFS" = "aufs" -a "$SAVE_LAYER" = "/pup_rw" ]; then
		busybox mount -o remount,noxino,noplink,ro -t $uniFS / / >/dev/null 2>&1
		sync
	fi
	if [ "$SAVEDEV" ]; then
		busybox mount -t $SAVEFS -o remount,ro $SAVEDEV /initrd${SAVE_LAYER} >/dev/null 2>&1
		if [ ! "$PIVOT_INITRD" ] ; then
			# lazy unmount savefile only if /initrd/files is not mounted
			umount-FULL -i -n -l /initrd${SAVE_LAYER} >/dev/null 2>&1 #-l is lazy unmount.
		fi
	fi
fi

# full installs end here
# also end here if not pivoting into initrd (rc.cleanup)
if [ ! "$PIVOT_INITRD" ] ; then
	rm -f /tmp/shutdown_pivot_initrd /tmp/debugshutdown /tmp/shutdownshell
	umount.crypto_LUKS all
	umount-FULL -in -a -r -d >/dev/null 2>&1
fi

# next: rc.cleanup

### END ###
